module.exports=new (function(){

    this.getHead=function(){
        return `
package  sophia.mmorpg.proto;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;

import org.apache.mina.core.buffer.IoBuffer;
import sophia.foundation.communication.core.ActionEventBase;
import java.nio.charset.Charset;
import java.util.ArrayList;

`;
    }

    this.space_def = '    ';

    this.getContentHead=function(name){
        var result="";
        result+=`public class ${name} extends ActionEventBase  {\n`;
        return result;
    }

    this.genProperty=function(javatype, propertyName, neednew, initValue) {
        var startSpace = this.space_def;
        var result = startSpace + '//m_' + propertyName + '\n';

        if(neednew)
        {
            result += startSpace + 'private '+ javatype +' m_' + propertyName + ' = new ' + javatype + '();\n';
        }
        else
        {
            result += startSpace + 'private '+ javatype +' m_' + propertyName + ' = ' + initValue + ';\n';
        }

        result += startSpace + 'public '+ javatype +' get' + propertyName + '(){\n';
        result += startSpace + this.space_def + 'return m_' + propertyName + ';\n';
        result += startSpace + '}\n';
        result += startSpace + 'public void set' + propertyName + '('+ javatype +' value){\n';
        result += startSpace + this.space_def + 'm_' + propertyName + ' = value;\n';
        result += startSpace + '}\n\n'; 

        return result;
    }

    this.getContent=function(name,fileds){
		//trim begin
		for(var filed of fileds){
			filed.type = filed.type.replace(/[\r\n\t]/g,"")
			filed.propertyName = filed.propertyName.replace(/[\r\n\t]/g,"")
			filed.propertyType = filed.propertyType.replace(/[\r\n\t]/g,"")
		}
		//trim end
		
        var result='';
        ////////////////////////////////////////////////   
        for(var filed of fileds){
            
                var isArray = (filed.type=='repeated');
                switch(filed.propertyType)
                {
                    case 'byte':
                        result+=this.genProperty(isArray?'ArrayList<Byte>':'Byte', filed.propertyName, isArray, "0");
                        break;
                    case 'string':
                        result+=this.genProperty(isArray?'ArrayList<String>':'String', filed.propertyName, isArray, '""');
                        break;
                    case 'bool':
					case 'boolean':
                        result+=this.genProperty(isArray?'ArrayList<Boolean>':'Boolean', filed.propertyName, isArray, "true");
                        break;
                    case 'double':
                        result+=this.genProperty(isArray?'ArrayList<double>':'double', filed.propertyName, isArray, "0");
                        break;
                    case 'float':
                        result+=this.genProperty(isArray?'ArrayList<float>':'float', filed.propertyName, isArray, "0");
                        break;
                    case 'int32':
                        result+=this.genProperty(isArray?'ArrayList<Integer>':'int', filed.propertyName, isArray, "0");
                        break;
                    case 'uint32':
                        result+=this.genProperty(isArray?'ArrayList<Integer>':'int', filed.propertyName, isArray, "0");
                        break;
					case 'int64':
					case 'uint64':
						result+=this.genProperty(isArray?'ArrayList<Long>':'Long', filed.propertyName, isArray, "0L");
						break;
                    case 'sint32':
                        result+=this.genProperty(isArray?'ArrayList<short>':'short', filed.propertyName, isArray, "0");
                        break;
                    case 'sint64'://没有，所以32位
                        result+=this.genProperty(isArray?'ArrayList<Integer>':'int', filed.propertyName, isArray, "0");
                        break;
                    case 'fixed32':
                    case 'fixed64':
                    case 'sfixed32':
                    case 'sfixed64':
                        result+=this.genProperty(isArray?'ArrayList<Integer>':'int', filed.propertyName, isArray, "0");
                        break;
                    default:
                        result+=this.genProperty(isArray?'ArrayList<'+filed.propertyType+'>': filed.propertyType, filed.propertyName, true, "null");
                        break;
                }
        }
		
		////////////////////////////////////////////////
		result += this.space_def + '@Override\n';
		result += this.space_def + 'public IoBuffer packBody(IoBuffer buffer) {\n';
		result += this.space_def + this.space_def + 'try{\n';
		result += this.space_def + this.space_def + this.space_def + 'JsonObject jsonObject = new JsonObject();\n';
		result += this.space_def + this.space_def + this.space_def + 'packJson(jsonObject);\n\n';
		result += this.space_def + this.space_def + this.space_def + 'String jsonStr = jsonObject.toString();\n';
		result += this.space_def + this.space_def + this.space_def + 'if( jsonStr == null ) jsonStr = "";\n';
		result += this.space_def + this.space_def + this.space_def + 'buffer.putShort((short)jsonStr.getBytes("UTF-8").length);\n';
		result += this.space_def + this.space_def + this.space_def + 'buffer.put(jsonStr.getBytes("UTF-8"));\n';
		result += this.space_def + this.space_def + '}catch(Exception e){\n';
		result += this.space_def + this.space_def + this.space_def + 'e.printStackTrace();\n';
		result += this.space_def + this.space_def + '}\n\n';
		result += this.space_def + this.space_def + ' return buffer;\n';
		result += this.space_def + '}\n\n';

        //////////////////////////////////////////////// 
        result += this.space_def + 'public void packJson(JsonObject jsonObject) {\n';
        result += this.space_def + 'try{\n';
		result += this.space_def + this.space_def + '@SuppressWarnings("unused")\n';
		result += this.space_def + this.space_def + 'int total = 0;\n';
		result += this.space_def + this.space_def + '@SuppressWarnings("unused")\n';
		result += this.space_def + this.space_def + 'JsonObject tmpJsObj = null;\n';
		result += this.space_def + this.space_def + '@SuppressWarnings("unused")\n';
		result += this.space_def + this.space_def + 'JsonArray jsArray = null;\n\n';

		if(name.indexOf('Proto') != 0)
		{
		result += this.space_def + this.space_def + 'jsonObject.addProperty("reqId", getRequestId());\n';
		result += this.space_def + this.space_def + 'jsonObject.addProperty("routeId", getActionEventId());\n';
		}

        function getWriteSigle(filed,lastSpace,isArray){
            var space = lastSpace;
            var result='';
            result += space + '//m_'+filed.propertyName+'\n';

            var opVarName = 'this.m_'+filed.propertyName;
            if(isArray)
            {
                opVarName = 'this.m_'+filed.propertyName+'.get(i)';
            }

            switch(filed.propertyType){
                case 'byte':
					if(isArray)
					{
						result += space + 'jsArray.add(new JsonPrimitive((byte)' + opVarName + '));';
					}
					else
					{
						result += space + 'jsonObject.addProperty("' + filed.propertyName + '", ' + opVarName + ');\n';
					}
                    break;
                case 'string':
					if(isArray)
					{
						result += space + 'jsArray.add(new JsonPrimitive(' + opVarName + '));';
					}
					else
					{
						result += space + 'jsonObject.addProperty("' + filed.propertyName + '", ' + opVarName + ');\n';
					}
                    break;
                case 'bool':
				case 'boolean':
                case 'double':
                case 'float':
                case 'int32':
                case 'int64':
                case 'uint32':
                case 'uint64':
                case 'sint32': 
                case 'sint64':
                case 'fixed32':
                case 'fixed64':
                case 'sfixed32':
                case 'sfixed64':
					if(isArray)
					{
						result += space + 'jsArray.add(new JsonPrimitive(' + opVarName + '));';
					}
					else
					{
						result += space + 'jsonObject.addProperty("' + filed.propertyName + '", ' + opVarName + ');\n';
					}
                    break;
                default:
					result += space + 'tmpJsObj = new JsonObject();\n';
					result += space + opVarName + '.packJson(tmpJsObj);\n';
					if(isArray)
					{
						result += space + 'jsArray.add(tmpJsObj);';
					}
					else
					{
						result += space + 'jsonObject.add("' + filed.propertyName + '", tmpJsObj);\n';
					}
                    break;
            }
            result += '\n';
            return result;
        }


        for(var filed of fileds){
            var startSpace = this.space_def + this.space_def;
            if(filed.type=='repeated'){
                result += startSpace + `total=this.m_${filed.propertyName}!=null?this.m_${filed.propertyName}.size():0;\n`
				result += startSpace + 'jsArray = new JsonArray();\n'
                result += startSpace + `if(total > 0){\n`
                result += startSpace + this.space_def + `for(short i=0;i<total;i++){\n`
                result += getWriteSigle(filed, startSpace + this.space_def + this.space_def, true);
                result += startSpace + this.space_def + `}\n`
                result += startSpace + `}\n`
				result += startSpace + 'jsonObject.add("' + filed.propertyName + '", jsArray);\n\n';
            }else{
                result+=getWriteSigle(filed, startSpace, false);
            }
        }
        result += this.space_def + '}catch(Exception e){\n';
        result += this.space_def + this.space_def + 'e.printStackTrace();\n';
        result += this.space_def + '}\n';
        result += '\n';

        result += this.space_def + this.space_def + 'return;\n';
        result += this.space_def + `}\n\n`;
		
		//////////////////////////////////////////////// 
		result += this.space_def + '@Override\n';
        result += this.space_def + 'public void unpackBody(IoBuffer buffer) {\n';
		result += this.space_def + this.space_def + 'try{\n';
		result += this.space_def + this.space_def + this.space_def + 'String content = getStringFromBuf(buffer);\n';
		result += this.space_def + this.space_def + this.space_def + 'JsonObject jsonObject = new JsonParser().parse(content).getAsJsonObject();\n';
		result += this.space_def + this.space_def + this.space_def + 'unpackJson(jsonObject);\n';
		result += this.space_def + this.space_def + '}catch(Exception e){\n';
		result += this.space_def + this.space_def + this.space_def + 'e.printStackTrace();\n';
		result += this.space_def + this.space_def + '}\n';
		result += this.space_def + this.space_def + 'return;\n';
		result += this.space_def + '}\n\n';
		
		
        //////////////////////////////////////////////// 
		result += this.space_def + '@Override\n';
        result += this.space_def + 'public void unpackJson(JsonObject jsonObject) {\n';
		result += this.space_def + this.space_def + '@SuppressWarnings("unused")\n';
		result += this.space_def + this.space_def + 'int total = 0;\n';
		result += this.space_def + this.space_def + '@SuppressWarnings("unused")\n';
		result += this.space_def + this.space_def + 'JsonArray jsArray = null;\n\n';	
		
        function getReadSigle(filed,lastSpace,isArray){
            var space=lastSpace;
            var result='';
            var space_next = "    ";
            result += space + '//m_'+filed.propertyName+'\n';

            var opVarName = 'm_'+filed.propertyName;
            if(isArray)
            {
                opVarName = 'tmp'+filed.propertyName;
            }
			
			if(isArray)
			{
				result += space + `if( jsArray.get(i) != null ) {\n`;
			}
			else
			{
				result += space + `if( jsonObject.get("${filed.propertyName}") != null ){\n`;
			}

            switch(filed.propertyType){
                case 'byte':
					if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsByte();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsByte();\n`;
					}
                    break;
                case 'string':
                    if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsString();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsString();\n`;
					}
                    break;
                case 'bool':
				case 'boolean':
                    if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsBoolean();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsBoolean();\n`;
					}
                    break;
                case 'double':
                    if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsDouble();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsDouble();\n`;
					}
                    break;
                case 'float':
                    if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsFloat();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsFloat();\n`;
					}
                    break;
                case 'int32':
                    if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsInt();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsInt();\n`;
					}
                    break;
                case 'uint32':
					if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsInt();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsInt();\n`;
						result += space + `if(${opVarName}<0) ${opVarName}=0;\n`;
					}
                    break;
				case 'int64':
				case 'uint64':
					if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsLong();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsLong();\n`;
						result += space + `if(${opVarName}<0) ${opVarName}=0L;\n`;
					}
					break;
                case 'sint32':
                    if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsShort();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsShort();\n`;
					}
                    break;
                case 'sint64':
                    if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsInt();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsInt();\n`;
					}
                    break;
                case 'fixed32':
                case 'fixed64':
                case 'sfixed32':
                case 'sfixed64':
                    if(isArray)
					{
						result += space + `${opVarName} = jsArray.get(i).getAsInt();\n`;
					}
					else
					{
						result += space + `${opVarName} = jsonObject.get("${filed.propertyName}").getAsInt();\n`;
					}
                    break;
                default:
					result += space + opVarName + ` = new ` + filed.propertyType + `();\n`;
                    if(isArray)
                    {
                        result += space + opVarName +`.unpackJson(jsArray.get(i).getAsJsonObject());\n`;
                    }
					else
					{
						result += space + opVarName +`.unpackJson(jsonObject.get("${filed.propertyName}").getAsJsonObject());\n`;
					}
                    break;
            }

			result += space + `}\n\n`;
            return result;
        }
		
		function getInitString(type){
			switch(type){
				case 'byte':
					return "0";
				case 'string':
					return "new String()";
				case 'bool':
				case 'boolean':
					return "True";
				case 'double':
					return "0";
				case 'float':
					return "0";
				case 'int32':
					return "0";
				case 'uint32':
					return "0";
				case 'int64':
					return "0L";
				case 'uint64':
					return "0L";
				case 'sint32':
					return "0";
				case 'sint64':
					return "0";
				case 'fixed32':
				case 'fixed64':
				case 'sfixed32':
				case 'sfixed64':
					return "0";
			}
			return "new " + type + "()";
		}
		
        for(var filed of fileds){
            var startSpaceUpk = this.space_def + this.space_def;
            if(filed.type=='repeated'){
				result += startSpaceUpk + 'this.m_'+filed.propertyName + '.clear();\n';
				result += startSpaceUpk + this.getType(filed.propertyType) + ' '+ 'tmp' + filed.propertyName + ' = ' + getInitString(filed.propertyType) + ';\n';
				
				result += startSpaceUpk + `if( jsonObject.get("${filed.propertyName}") != null) {\n`;
				result += startSpaceUpk + `jsArray = jsonObject.get("${filed.propertyName}").getAsJsonArray();\n`;
				result += startSpaceUpk + `total = jsArray.size();\n`;
                result += startSpaceUpk + `if(total > 0){\n`;
                result += startSpaceUpk + this.space_def + `for(int i = 0; i < total; i++){\n`;
                result += getReadSigle(filed,startSpaceUpk + this.space_def + this.space_def, true);
                result += startSpaceUpk + this.space_def + this.space_def + 'this.m_'+filed.propertyName + '.add(' + 'tmp' + filed.propertyName + ');\n';
                result += startSpaceUpk + this.space_def + `}\n`
                result += startSpaceUpk + `}\n`
				result += startSpaceUpk + `}\n\n`
            }else{
                result += getReadSigle(filed, startSpaceUpk, false);
            }
        }
        result += this.space_def + '}\n\n';
		
		//重载name函数
		result += this.space_def + '@Override\n';
		result += this.space_def + 'public String getName() {\n';
		result += this.space_def + this.space_def + 'return "'+ name +'";\n';
		result += this.space_def + '}\n\n';

        //辅助函数
		result += this.space_def + '@SuppressWarnings("unused")\n';
        result += this.space_def + 'private String getStringFromBuf(IoBuffer bufferIn){\n';
        result += this.space_def + this.space_def +'String ret = "";\n';
        result += this.space_def + this.space_def +'try {\n';
        result += this.space_def + this.space_def + this.space_def + 'short str_len = bufferIn.getShort();\n';
		result += this.space_def + this.space_def + this.space_def + 'if(str_len < 1) return ret;\n';
        result += this.space_def + this.space_def + this.space_def + 'byte[] str_content = new byte[str_len];\n';
        result += this.space_def + this.space_def + this.space_def + 'bufferIn.get(str_content, bufferIn.arrayOffset(), str_len);\n';
        result += this.space_def + this.space_def + this.space_def + `ret=IoBuffer.wrap(str_content).getString(Charset.forName("UTF-8").newDecoder());\n`;
        result += this.space_def + this.space_def + '} catch (Exception e1) {\n';
        result += this.space_def + this.space_def + this.space_def + 'e1.printStackTrace();\n';
        result += this.space_def + this.space_def + '}\n';
        result += this.space_def + this.space_def + 'return ret;\n';
		result += this.space_def + '}\n\n';

        return result;
    }

    this.getContentEnd=function(name){
        var result="}\n\n\n\n";
        return result;
    }

    this.getEnd=function(){
        return `})(p || (p = {}));`;
    }
    
    this.getType=function(type){
        switch(type){
            case 'byte':
                return "byte";
            case 'string':
                return "String";
            case 'bool':
			case 'boolean':
                return "Boolean";
            case 'double':
                return "Double";
            case 'float':
                return "float";
            case 'int32':
                return "int";
            case 'uint32':
                return "int";
            case 'int64':
                return "Long";
            case 'uint64':
                return "Long";
            case 'sint32':
                return "short";
            case 'sint64':
                return "int";
            case 'fixed32':
            case 'fixed64':
            case 'sfixed32':
            case 'sfixed64':
                return "int";
        }
        return type;
    }
})()